package com.link.cloud.config.mybatis;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;
import com.github.pagehelper.PageHelper;
import com.link.cloud.config.mybatis.properties.MybatisProperties;
import com.link.cloud.config.mybatis.properties.PageHelperProperties;

@Configuration
@EnableTransactionManagement
public class MybatisConfig{
	
	private static Logger logger = LoggerFactory.getLogger(MybatisConfig.class);
	
	@Bean
    @ConfigurationProperties(prefix = "platform.mybatis")
    public MybatisProperties myBatisProperties() {
        return new MybatisProperties();
    }
	
	@Bean(initMethod = "init", destroyMethod = "close")
    @ConfigurationProperties(prefix = "platform.datasource")
    public DataSource dataSource() {
        logger.debug("Platform - MyBatis - DataSource : new");
        DruidDataSource ds = new com.alibaba.druid.pool.DruidDataSource();

        try {
            ds.setFilters("stat");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        ds.setMaxActive(20);
        ds.setInitialSize(1);
        ds.setMaxWait(60000);
        ds.setMinIdle(1);
        ds.setTimeBetweenConnectErrorMillis(6000);
        ds.setMinEvictableIdleTimeMillis(300000);
        ds.setValidationQuery(" select 'x' ");
        ds.setTestWhileIdle(true);
        ds.setTestOnBorrow(false);
        ds.setTestOnReturn(false);
        return ds;
    }
	
	@Bean
    @Autowired
    public SqlSessionFactory sqlSessionFactory(MybatisProperties mybatisProperties) throws Exception {

        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

        Properties configuration = new Properties();
        // lazyLoadingEnabled：true使用延迟加载，false禁用延迟加载。默认为true
        configuration.setProperty("lazyLoadingEnabled", "true");
        // aggressiveLazyLoading：true启用时，当延迟加载开启时访问对象中一个懒对象属性时，将完全加载这个对象的所有懒对象属性。
        // false，当延迟加载时，按需加载对象属性（即访问对象中一个懒对象属性，不会加载对象中其他的懒对象属性）。默认为true
        configuration.setProperty("aggressiveLazyLoading", "false");
        bean.setConfigurationProperties(configuration);

        bean.setDataSource(dataSource());
        bean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackage());
        bean.setTypeHandlersPackage(mybatisProperties.getTypeHandlersPackage());

        // 分页插件

        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();

        PageHelperProperties page = mybatisProperties.getPage();
        if (StringUtils.isNotBlank(page.getDialect())) {
            properties.setProperty("dialect", page.getDialect());
        }

        // <!-- 该参数默认为false -->
        // <!-- 设置为true时，会将RowBounds第一个参数offset当成pageNum页码使用 -->
        // <!-- 和startPage中的pageNum效果一样-->
        if (StringUtils.isNotBlank(page.getOffsetAsPageNum())) {
            properties.setProperty("offsetAsPageNum", page.getOffsetAsPageNum());
        }

        // <!-- 该参数默认为false -->
        // <!-- 设置为true时，使用RowBounds分页会进行count查询 -->
        if (StringUtils.isNotBlank(page.getRowBoundsWithCount())) {
            properties.setProperty("rowBoundsWithCount", page.getRowBoundsWithCount());
        }

        // <!-- 设置为true时，如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
        // <!-- （相当于没有执行分页查询，但是返回结果仍然是Page类型）-->
        if (StringUtils.isNotBlank(page.getPageSizeZero())) {
            properties.setProperty("pageSizeZero", page.getPageSizeZero());
        }

        // <!-- 3.3.0版本可用 - 分页参数合理化，默认false禁用 -->
        // <!-- 启用合理化时，如果pageNum<1会查询第一页，如果pageNum>pages会查询最后一页 -->
        // <!-- 禁用合理化时，如果pageNum<1或pageNum>pages会返回空数据 -->
        if (StringUtils.isNotBlank(page.getReasonable())) {
            properties.setProperty("reasonable", page.getReasonable());
        }

        // <!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
        // <!-- 增加了一个`params`参数来配置参数映射，用于从Map或ServletRequest中取值 -->
        // <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默认值 -->
        // <!-- 不理解该含义的前提下，不要随便复制该配置 -->
        // properties.setProperty("params", "pageNum=start;pageSize=limit;");
        // <!-- 支持通过Mapper接口参数来传递分页参数 -->
        if (StringUtils.isNotBlank(page.getSupportMethodsArguments())) {
            properties.setProperty("supportMethodsArguments", page.getSupportMethodsArguments());
        }

        // <!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
        if (StringUtils.isNotBlank(page.getReturnPageInfo())) {
            properties.setProperty("returnPageInfo", page.getReturnPageInfo());
        }

        pageHelper.setProperties(properties);
        // 添加插件
        bean.setPlugins(new Interceptor[] { pageHelper });

        // 添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources(mybatisProperties.getMapperLocations()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bean.getObject();
    }

    @Bean
    @Autowired
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean(name = "transaction")
    public DataSourceTransactionManager dataSourceTransactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

}
